package com.faner4cloud.yun.common.util.page;

import cn.hutool.core.bean.BeanUtil;
import com.faner4cloud.yun.common.util.BeanUtils;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;
import reactor.core.scheduler.Schedulers;

import java.util.concurrent.ExecutorService;
import java.util.function.Function;
import java.util.stream.Collectors;

/**
 * @author ...zz
 * @version v1
 * @summary desc
 * @since 2022/8/2 4:19 PM
 */
public class PaginationUtils {

	public static <T, R> Pagination<R> convertType(Pagination<T> source, Class<R> targetClass) {
		if (source == null) {
			return null;
		}
		Pagination<R> pagination = new Pagination<>();
		pagination.setPageNo(source.getPageNo());
		pagination.setPageSize(source.getPageSize());
		pagination.setTotalCount(source.getTotalCount());
		pagination.setPageList(BeanUtils.convertType(source.getPageList(), targetClass));
		return pagination;
	}

	public static <T, R> Pagination<R> jsonConvertType(Pagination<T> source, Class<R> targetClass) {
		if (source == null) {
			return null;
		}
		Pagination<R> pagination = new Pagination<>();
		pagination.setPageNo(source.getPageNo());
		pagination.setPageSize(source.getPageSize());
		pagination.setTotalCount(source.getTotalCount());
		pagination.setPageList(BeanUtils.jsonConvertType(source.getPageList(), targetClass));
		return pagination;
	}

	/**
	 * @param pagination 分页对象
	 * @param mapper     转换方法
	 * @param <T>        原始
	 * @param <R>        返回
	 * @return
	 * @author ouyang
	 * @version v1
	 * @summary
	 * @since 2017-12-21 15:18:28
	 */
	public static <T, R> Pagination<R> convert(Pagination<T> pagination, Function<T, R> mapper,
											   ExecutorService executorService) {
		return Mono.just(new Pagination<R>(pagination.getPageNo(), pagination.getPageSize()))
			.map(page -> {
				page.setTotalCount(pagination.getTotalCount());
				if (pagination.getPageList() == null || pagination.getPageList().size() == 0) {
					return page;
				}
				page.setPageList(Flux.fromIterable(pagination.getPageList())
					.zipWith(Flux.range(1, Integer.MAX_VALUE),
						(id, sortNo) -> new BeanUtils.SortView<T, R>(sortNo, id))
					.flatMap(sortView -> Mono.fromCallable(() -> sortView.setRet(
							mapper.apply(sortView.getTarget()))).subscribeOn(
							Schedulers.fromExecutor(executorService)),
						pagination.getPageSize())
					.sort()
					.map(sv -> sv.getRet())
					.collect(Collectors.toList())
					.block());
				return page;
			})
			.block();
	}

}
